package cn.net.shuxing.yifu.common.service;

import cn.net.shuxing.yifu.common.bean.*;
import cn.net.shuxing.yifu.common.constant.DealScene;
import cn.net.shuxing.yifu.common.constant.DealState;
import cn.net.shuxing.yifu.common.constant.DealType;
import cn.net.shuxing.yifu.common.dto.DealRecordDto;
import cn.net.shuxing.yifu.common.dto.KLineDto;
import cn.net.shuxing.yifu.common.dto.KLinePartOne;
import cn.net.shuxing.yifu.common.dto.KLinePartTwo;
import cn.net.shuxing.yifu.common.mapper.DealHistoryMapper;
import cn.net.shuxing.yifu.common.util.JedisUtil;
import cn.net.shuxing.yifu.common.util.RedisKeyCreator;
import cn.net.shuxing.yifu.common.util.TimeExample;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

import static java.math.BigDecimal.ROUND_HALF_UP;

@Service
public class KLineService {

    @Autowired
    private DealHistoryService dealHistoryService;

    @Autowired
    private HangBuyService hangBuyService;

    @Autowired
    private HangSaleService hangSaleService;

    @Autowired
    private UserDealHistoryService userDealHistoryService;

    @Autowired
    private JedisUtil jedisUtil;

    @Autowired
    private CoinTypeService coinTypeService;

    @Autowired
    private CoinRatioService coinRatioService;



//    public KLineDto falsegetKLineDataByMinute(Integer coinTypeId, LocalDateTime startTime, LocalDateTime endTime, Integer minuteUnit) {
//        LocalDateTime startDateTime = startTime;
//        KLineDto dto = new KLineDto();
//
//        dto.setOpenPrice(new BigDecimal(jedisUtil.get(RedisKeyCreator.openPrice(coinTypeId))));
//        dto.setGain(coinRatioService.calculateCoinGain(coinTypeId));
//        dto.setTodayDealCount(new BigDecimal(jedisUtil.get(RedisKeyCreator.todayDealCount(coinTypeId))));
//        dto.setHighestPrice(new BigDecimal(jedisUtil.get(RedisKeyCreator.coinHighestPrice(coinTypeId))));
//        dto.setLowestPrice(new BigDecimal(jedisUtil.get(RedisKeyCreator.coinLowestPrice(coinTypeId))));
//
//        /**第一部分**/
//        ArrayList<KLinePartOne> kLinePartOnes = new ArrayList<>();
//        ArrayList<KLinePartTwo> kLinePartTwos = new ArrayList<>();
//        for (int i = 50; i > 0; i--) {
//            startDateTime = startDateTime.plusMinutes(0 - minuteUnit * i);
//            LocalDateTime tempEndTime = startDateTime.plusMinutes(0 - minuteUnit * (i - 1));
//            TimeExample example = new TimeExample(UserDealHistory.class);
//            example.between("createTime", startDateTime, tempEndTime);
//            example.setOrderByClause("create_time ASC");
//            List<UserDealHistory> dealHistoryList = userDealHistoryService.getsByExample(example);
//            BigDecimal lowestPrice = new BigDecimal(0);
//            BigDecimal highestPrice = new BigDecimal(0);
//            BigDecimal lastTimeHighestPrice = new BigDecimal(0);
//            BigDecimal totalDealCount = new BigDecimal(0);
//            BigDecimal diff = new BigDecimal(0);
//            BigDecimal macd = new BigDecimal(0);
//            BigDecimal dea = new BigDecimal(0);
//            BigDecimal ema12 = new BigDecimal(0);
//            BigDecimal ema26 = new BigDecimal(0);
//            if (dealHistoryList != null) {
//                KLinePartOne kLinePartOne = new KLinePartOne();
//                kLinePartOne.setOpenPrice(dealHistoryList.get(0).getDealAliveCoinCount());
//                BigDecimal momentColsePrice = dealHistoryList.get(dealHistoryList.size() - 1).getDealAliveCoinCount();
//                kLinePartOne.setClosePrice(momentColsePrice);
//                for (int j = 0; j < dealHistoryList.size(); j++) {
//                    //第一张图
//                    BigDecimal price = dealHistoryList.get(j).getSinglePrice();
//                    if (price.compareTo(lowestPrice) < 0) {
//                        lowestPrice = price;
//                    }
//                    if (price.compareTo(highestPrice) > 0) {
//                        highestPrice = price;
//                    }
//                    kLinePartOne.setLowestPrice(lowestPrice);
//                    kLinePartOne.setHighestPrice(highestPrice);
//                    if (j == 0) {
//                        kLinePartOne.setGain(new BigDecimal(0));
//                        ema12 = (ema12.multiply(new BigDecimal(11)).divide(new BigDecimal(13), 8, BigDecimal.ROUND_HALF_UP)).add(momentColsePrice.multiply(new BigDecimal(2).divide(new BigDecimal(13))));
//                        ema26 = (ema26.multiply(new BigDecimal(25)).divide(new BigDecimal(27), 8, BigDecimal.ROUND_HALF_UP)).add(momentColsePrice.multiply(new BigDecimal(2).divide(new BigDecimal(27))));
//                        dea = (dea.multiply(new BigDecimal(8)).divide(new BigDecimal(10))).add(diff.multiply(new BigDecimal(2).divide(new BigDecimal(10))));
//                    } else {
//                        kLinePartOne.setGain(lastTimeHighestPrice.subtract(highestPrice).divide(highestPrice));
//                    }
//                    lastTimeHighestPrice = highestPrice;
//                    totalDealCount = totalDealCount.add(dealHistoryList.get(i).getDealAliveCoinCount());
//                    kLinePartOne.setTotalDealCount(totalDealCount);
//                    //第二张图
//                    kLinePartOne.setVolume(totalDealCount);
//                    //第三张图
//                    diff = ema12.subtract(ema26);
//                    macd = diff.subtract(diff);
//                    kLinePartOne.setMacd(macd);
//                    kLinePartOne.setDiff(diff);
//                    kLinePartOne.setDea(dea);
//                    kLinePartOnes.add(kLinePartOne);
//                }
//                /**第二部分**/
//
//                if (dealHistoryList != null && !dealHistoryList.isEmpty()) {
//                    KLinePartTwo kLinePartTwo = new KLinePartTwo();
//                    for (UserDealHistory userDealHistory : dealHistoryList) {
//                        BigDecimal dealPrice = userDealHistory.getSinglePrice();
//                        BigDecimal dealCount = userDealHistory.getDealAliveCoinCount();
//                        ArrayList<DealRecordDto> dealRecordDtos = new ArrayList<>();
//                        DealRecordDto dealRecordDto = new DealRecordDto();
//                        if (kLinePartTwos != null && !kLinePartTwos.isEmpty()) {
//                            for (KLinePartTwo linePartTwo : kLinePartTwos) {
//                                BigDecimal twoPrice = linePartTwo.getDealPrice();
//                                BigDecimal twoCount = linePartTwo.getDealCount();
//                                if (dealPrice.compareTo(twoPrice) == 0) {
//                                    dealCount = dealCount.add(twoCount);
//                                    List<DealRecordDto> dealRecordList = linePartTwo.getDealRecordList();
//                                    dealRecordDto.setDealPrice(dealPrice);
//                                    dealRecordDto.setDealAliveCoinCount(dealCount);
//                                    dealRecordDto.setCreateTime(userDealHistory.getCreateTime());
//                                    dealRecordDto.setDealType(userDealHistory.getDealType());
//                                    dealRecordList.add(dealRecordDto);
//                                    linePartTwo.setDealRecordList(dealRecordList);
//                                }else {
//                                    kLinePartTwo.setDealCount(dealCount);
//                                    kLinePartTwo.setDealPrice(dealPrice);
//                                    dealRecordDto.setDealPrice(dealPrice);
//                                    dealRecordDto.setDealAliveCoinCount(dealCount);
//                                    dealRecordDto.setDealType(userDealHistory.getDealType());
//                                    dealRecordDto.setCreateTime(userDealHistory.getCreateTime());
//                                    dealRecordDtos.add(dealRecordDto);
//                                    kLinePartTwo.setDealRecordList(dealRecordDtos);
//                                    kLinePartTwos.add(kLinePartTwo);
//                                }
//                            }
//                        }
//                    }
//                }
//            }
//        }
//        List<DealRecordDto> hangBuy = hangBuyService.getByCoinTypeIdAndState(coinTypeId);
//        List<DealRecordDto> hangSale = hangSaleService.getByCoinTypeIdAndState(coinTypeId);
//        dto.setKLinePartOneList(kLinePartOnes);
//        dto.setKLinePartTwoList(kLinePartTwos);
//        dto.setHangBuyList(hangBuy);
//        dto.setHangSaleList(hangSale);
//        return dto;
//    }


//    public List<Map<String, Object>> getDefaultKLineData(LocalDateTime startTime, LocalDateTime endTime, Integer minuteUnit) {
//        LocalDateTime startDateTime = startTime;
//        List<Map<String, Object>> data = new ArrayList<>();
//
//        startDateTime = startDateTime.plusMinutes(0 - minuteUnit);
//        LocalDateTime tempEndTime = startDateTime.plusMinutes(minuteUnit);
//        Map<String, Object> oldDataMap = null;
//        TimeExample example = new TimeExample(UserDealHistory.class);
//        example.between("createTime", startDateTime, tempEndTime);
//        List<UserDealHistory> dealHistoryList = userDealHistoryService.getsByExample(example);
//        oldDataMap = getUserDataMap(dealHistoryList);
//
//        startDateTime = startDateTime.plusMinutes(minuteUnit);
//        tempEndTime = startDateTime.plusMinutes(minuteUnit);
//        LocalDateTime tempStartTime = startTime;
//
//        example = new TimeExample(UserDealHistory.class);
//        example.between("createTime", startTime, endTime);
//        dealHistoryList = userDealHistoryService.getsByExampleWithoutComplete(example);
//        List<List<UserDealHistory>> resultList = new ArrayList<>();
//        int i = 0;
//        while (tempEndTime.compareTo(endTime) <= 0) {
//            List<UserDealHistory> dataList = new ArrayList<>();
//            if (!dealHistoryList.isEmpty()) {
//                while (true) {
//                    if (i == 23) {
//                        System.out.println();
//                    }
//                    UserDealHistory dealHistory = dealHistoryList.get(i);
//                    if (dealHistory.getCreateTime().compareTo(tempStartTime) >= 0 && dealHistory.getCreateTime().compareTo(tempEndTime) < 0) {
//                        dataList.add(dealHistory);
//                        if (i >= dealHistoryList.size() - 1) {
//                            break;
//                        }
//                        i++;
//                    } else {
//                        break;
//                    }
//
//                }
//            }
//
//            resultList.add(dataList);
//            tempEndTime = tempEndTime.plusMinutes(minuteUnit);
//            tempStartTime = tempStartTime.plusMinutes(minuteUnit);
//        }
//        for (List<UserDealHistory> dealHistoryList1 : resultList) {
//            Map<String, Object> dataMap = getUserDataMap(dealHistoryList1);
//            tempEndTime = tempEndTime.plusMinutes(minuteUnit);
//            tempStartTime = tempStartTime.plusMinutes(minuteUnit);
//            dataMap.put("time", tempStartTime);
//            BigDecimal gain = calculateGain((BigDecimal) dataMap.get("highestPrice"), (BigDecimal) oldDataMap.get("highestPrice"));
//            dataMap.put("gain", gain);
//            data.add(dataMap);
//            oldDataMap = dataMap;
//
//        }
//
//        return data;
//        /*
//        {
//            startPrice: 起始价格,
//            endPrice: 结束价格,
//            highestPrice: 最高价,
//            lowestPrice: 最低价,
//            dealCount: 交易量,
//            time: 起始时间,
//            gain: 涨幅
//        }
//         */
//    }

        private BigDecimal calculateGain (BigDecimal highestPrice, BigDecimal highestPrice1){
            if (highestPrice1.compareTo(new BigDecimal(0)) == 0) {
                if (highestPrice.compareTo(new BigDecimal(0)) == 0)
                    return new BigDecimal(0);
                return new BigDecimal(1);
            }

            BigDecimal divide = highestPrice.divide(highestPrice1, 8, ROUND_HALF_UP);
            return divide.subtract(new BigDecimal(1));
        }

        /**
         * @param dealHistoryList
         * @return {
         * <p>
         * }
         */
        private Map<String, Object> getDataMap (List < DealHistory > dealHistoryList) {
            Map<String, Object> dataMap = new HashMap<>();
            if (dealHistoryList == null || dealHistoryList.isEmpty()) {
                dataMap.put("startPrice", new BigDecimal(0));
                dataMap.put("endPrice", new BigDecimal(0));
                dataMap.put("highestPrice", new BigDecimal(0));
                dataMap.put("lowestPrice", new BigDecimal(0));
                dataMap.put("dealCount", new BigDecimal(0));
                return dataMap;
            }
            dataMap.put("startPrice", dealHistoryList.get(0).getSinglePrice());
            dataMap.put("endPrice", dealHistoryList.get(dealHistoryList.size() - 1).getSinglePrice());
            dealHistoryList.sort((x, y) -> {
                return x.getSinglePrice().multiply(x.getDealAliveCoinCount()).compareTo(y.getSinglePrice().multiply(y.getDealAliveCoinCount()));
            });
            dataMap.put("highestPrice", dealHistoryList.get(0).getSinglePrice());
            dataMap.put("lowestPrice", dealHistoryList.get(dealHistoryList.size() - 1).getSinglePrice());
            BigDecimal dealCount = new BigDecimal(0);
            for (DealHistory dealHistory : dealHistoryList) {
                dealCount = dealCount.add(dealHistory.getDealAliveCoinCount());
            }
            dataMap.put("dealCount", dealCount);
            return dataMap;
        }

        private Map<String, Object> getUserDataMap (List < UserDealHistory > dealHistoryList) {
            Map<String, Object> dataMap = new HashMap<>();
            if (dealHistoryList == null || dealHistoryList.isEmpty()) {
                dataMap.put("startPrice", new BigDecimal(0));
                dataMap.put("endPrice", new BigDecimal(0));
                dataMap.put("highestPrice", new BigDecimal(0));
                dataMap.put("lowestPrice", new BigDecimal(0));
                dataMap.put("dealCount", new BigDecimal(0));
                return dataMap;
            }
            dataMap.put("startPrice", dealHistoryList.get(0).getSinglePrice());
            dataMap.put("endPrice", dealHistoryList.get(dealHistoryList.size() - 1).getSinglePrice());
            dealHistoryList.sort((x, y) -> {
                return x.getSinglePrice().multiply(x.getDealAliveCoinCount()).compareTo(y.getSinglePrice().multiply(y.getDealAliveCoinCount()));
            });
            dataMap.put("highestPrice", dealHistoryList.get(0).getSinglePrice());
            dataMap.put("lowestPrice", dealHistoryList.get(dealHistoryList.size() - 1).getSinglePrice());
            BigDecimal dealCount = new BigDecimal(0);
            for (UserDealHistory dealHistory : dealHistoryList) {
                dealCount = dealCount.add(dealHistory.getDealAliveCoinCount());
            }
            dataMap.put("dealCount", dealCount);
            return dataMap;
        }

        public List<Map<String, Object>> getDeepKLineBuyData () {
            List<Map<String, Object>> data = new ArrayList<>();

            TimeExample example = new TimeExample(HangBuy.class);
            example.equals("state", DealState.DEALING);
            List<HangBuy> hangBuyList = hangBuyService.getsByExampleWithoutComplete(example);
            hangBuyList.sort((x, y) -> {
                return x.getSinglePrice().compareTo(y.getSinglePrice());
            });

            Map<String, Object> dataMap = new HashMap<>();
            if (!hangBuyList.isEmpty()) {
                dataMap.put("singlePrice", hangBuyList.get(0).getSinglePrice());
                dataMap.put("dealCount", hangBuyList.get(0).getAliveCoinCount());
            } else {
                dataMap.put("singlePrice", new BigDecimal(0));
                dataMap.put("dealCount", new BigDecimal(0));
            }


            data.add(dataMap);
            for (int i = 1; i < hangBuyList.size(); i++) {
                HangBuy oldHangBuy = hangBuyList.get(i - 1);
                HangBuy currentHangBuy = hangBuyList.get(i);
                if (currentHangBuy.getSinglePrice().equals(oldHangBuy.getSinglePrice())) {
                    BigDecimal dealCount = (BigDecimal) dataMap.get("dealCount");
                    dealCount = dealCount.add(currentHangBuy.getAliveCoinCount());
                    dataMap.put("dealCount", dealCount);
                } else {
                    dataMap = new HashMap<>();
                    dataMap.put("singlePrice", currentHangBuy.getSinglePrice());
                    dataMap.put("dealCount", currentHangBuy.getAliveCoinCount());
                    data.add(dataMap);
                }
            }


            return data;
        }

        public List<Map<String, Object>> getDeepKLineSaleData () {
            List<Map<String, Object>> data = new ArrayList<>();

            TimeExample example = new TimeExample(HangSale.class);
            example.equals("state", DealState.DEALING);

            List<HangSale> hangSaleList = hangSaleService.getsByExampleWithoutComplete(example);
            hangSaleList.sort((x, y) -> {
                return x.getSinglePrice().compareTo(y.getSinglePrice());
            });

            Map<String, Object> dataMap = new HashMap<>();
            if (!hangSaleList.isEmpty()) {
                dataMap.put("singlePrice", hangSaleList.get(0).getSinglePrice());
                dataMap.put("dealCount", hangSaleList.get(0).getAliveCoinCount());
            } else {
                dataMap.put("singlePrice", new BigDecimal(0));
                dataMap.put("dealCount", new BigDecimal(0));
            }
            data.add(dataMap);
            for (int i = 1; i < hangSaleList.size(); i++) {
                HangSale oldHangSale = hangSaleList.get(i - 1);
                HangSale currentHangSale = hangSaleList.get(i);
                if (currentHangSale.getSinglePrice().equals(oldHangSale.getSinglePrice())) {
                    BigDecimal dealCount = (BigDecimal) dataMap.get("dealCount");
                    dealCount = dealCount.add(currentHangSale.getAliveCoinCount());
                    dataMap.put("dealCount", dealCount);
                } else {
                    dataMap = new HashMap<>();
                    dataMap.put("singlePrice", currentHangSale.getSinglePrice());
                    dataMap.put("dealCount", currentHangSale.getAliveCoinCount());
                    data.add(dataMap);
                }
            }
            return data;
        }

        public List<Map<String, Object>> getDeepTradeKLineData (Integer dealScene){
            List<Map<String, Object>> data = new ArrayList<>();

            List<DealHistory> dealHistoryList = dealHistoryService.getAll();
            dealHistoryList.sort((x, y) -> {
                return x.getSinglePrice().compareTo(y.getSinglePrice());
            });

            Map<String, Object> dataMap = new HashMap<>();
            if (!dealHistoryList.isEmpty()) {
                dataMap.put("singlePrice", dealHistoryList.get(0).getSinglePrice());
                dataMap.put("dealCount", dealHistoryList.get(0).getDealAliveCoinCount());
            } else {
                dataMap.put("singlePrice", new BigDecimal(0));
                dataMap.put("dealCount", new BigDecimal(0));
            }
            data.add(dataMap);
            for (int i = 1; i < dealHistoryList.size(); i++) {
                DealHistory oldDealHistory = dealHistoryList.get(i - 1);
                DealHistory currentDealHistory = dealHistoryList.get(i);
                if (currentDealHistory.getSinglePrice().equals(oldDealHistory.getSinglePrice())) {
                    BigDecimal dealCount = (BigDecimal) dataMap.get("dealCount");
                    dealCount = dealCount.add(currentDealHistory.getDealAliveCoinCount());
                    dataMap.put("dealCount", dealCount);
                } else {
                    dataMap = new HashMap<>();
                    dataMap.put("singlePrice", currentDealHistory.getSinglePrice());
                    dataMap.put("dealCount", currentDealHistory.getDealAliveCoinCount());
                    data.add(dataMap);
                }
            }


            return data;
        }


        public List<Map<String, Object>> getDefaultKLineDataByMonth (LocalDateTime startTime, LocalDateTime
        endTime, Integer monthCount){
            LocalDateTime startDateTime = startTime;
            List<Map<String, Object>> data = new ArrayList<>();

            startDateTime = startDateTime.plusMonths(0 - monthCount);
            LocalDateTime tempEndTime = startDateTime.plusMonths(monthCount);
            Map<String, Object> oldDataMap = null;
            TimeExample example = new TimeExample(DealHistory.class);
            example.between("createTime", startDateTime, tempEndTime);
            example.setOrderByClause("id DESC");
            List<DealHistory> dealHistoryList = dealHistoryService.getsByExampleWithoutComplete(example);
            oldDataMap = getDataMap(dealHistoryList);

            startDateTime = startDateTime.plusMonths(monthCount);
            tempEndTime = startDateTime.plusMonths(monthCount);
            LocalDateTime tempStartTime = startTime;

            while (tempEndTime.compareTo(endTime) <= 0) {
                tempEndTime = tempEndTime.plusMonths(1);
                tempStartTime = tempStartTime.plusMonths(1);
                example = new TimeExample(UserDealHistory.class);
                example.between("createTime", tempStartTime, tempEndTime);
                dealHistoryList = dealHistoryService.getsByExampleWithoutComplete(example);
                Map<String, Object> dataMap = getDataMap(dealHistoryList);
                dataMap.put("time", startTime);
                BigDecimal gain = calculateGain((BigDecimal) dataMap.get("highestPrice"), (BigDecimal) oldDataMap.get("highestPrice"));
                dataMap.put("gain", gain);
                data.add(dataMap);
                oldDataMap = dataMap;
            }

            return data;
        }
    }
